/**
* @file    hi_hal_uartmsg.c
* @brief   uart message struct and interface declaration
*
* Copyright (C), 2016-2019, Hisilicon Tech. Co., Ltd.
*
* @author    IP Camera Reference Develop Team
* @date       2019/1/5
* @version   1.0

*/


#include "hi_hal_uartmsg_conf.h"
#include "hi_hal_uartmsg.h"
#include "kfifo.h"
#include "hi_hal_common.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */

#define                         RD_MSGBUF_LEN    128


HI_BOOL                             g_bUartHostInit  = HI_FALSE;
PFN_HI_HAL_UARTMSG_RCV_CALLBACK     g_cbkUartHostRcv = HI_NULL;
static pthread_t                    g_tUartHostDetect;
static pthread_mutex_t              s_tUartHostMutex;
static HI_U8                        g_USART_Receive_Buf[UART2_BUF_LEN];
static struct kfifo                 g_UartRecvFifo;
static HI_U8                        g_frameBuf[UF_MAX_LEN];
HI_S32                              g_s32gUart2Fd = -1;

static char bUartPause = 0;

static long g_timStamp[4];
static long getTimeUsec(HI_VOID)
{
    struct timeval t;
    gettimeofday(&t, 0);
    return (long)((long)t.tv_sec * 1000 * 1000 + t.tv_usec);
}

static void PrintTimeStamp(void)
{
    for (int i = 0; i < sizeof(g_timStamp) / sizeof(g_timStamp[0]); i++)
    {
        MLOGD("time stamp %d: %ld: \n", i, g_timStamp[i]);
    }

    return;
}

HI_S32 HI_HAL_UART_SetPause(char bPause)
{
    bUartPause = bPause;
    return 0;
}

HI_S32 HI_HAL_UART_IsPause(void)
{
    return bUartPause;
}

static HI_S32 HI_HAL_UART_RecvData(HI_S32 fd, HI_U8* pBuf, HI_U32 bufLen)
{
    HI_S32 retReadLen = 0;
    HI_U8  len = 0;
    HI_U8  rec_len = __kfifo_len(&g_UartRecvFifo);

    if (rec_len >= UF_MIN_LEN)
    {
        if (UARTMSG_MSGDATA_HEAD == g_UartRecvFifo.buffer[(g_UartRecvFifo.out + UF_START) & (g_UartRecvFifo.size - 1)])
        {
            len = g_UartRecvFifo.buffer[(g_UartRecvFifo.out + UF_LEN) & (g_UartRecvFifo.size - 1)];

            if (len == 0)
            {
                __kfifo_get(&g_UartRecvFifo, pBuf, 1);                           //当前的命令长度为0，丢弃
                MLOGD("discard byte: 0X%02X \n" , pBuf[0]);
            }
            else if ((rec_len >= len) && (bufLen >= len))
            {
                retReadLen = __kfifo_get(&g_UartRecvFifo, pBuf, len);
            }
        }
        else
        {
            __kfifo_get(&g_UartRecvFifo, pBuf, 1);                              //如果当前位置不是命令起始标志，则丢弃
            MLOGD("discard byte: 0X%02X \n" , pBuf[0]);
        }
    }

    return retReadLen;
}

static void print_buffer(unsigned char *buf, int size)
{
    int i = 0;
    int offset = 0;
    char printBuf[2048] = "";

    sprintf(printBuf + offset, "%s", "[ ");
    offset += 2;
    
    for (i = 0; i < size; i++)
    {
        sprintf(printBuf + offset, "%02x ", buf[i]);
        offset += 3;
    }

    sprintf(printBuf + offset, "%s", "]");

    printf("print_buffer: %s\n", printBuf);
    
}

static HI_VOID* UARTOST_Thread(HI_VOID* pPara)
{

    int             ret;
    unsigned char   rbuf[RD_MSGBUF_LEN];
    int             putLen;
    HI_S32          readLen = 0;
    fd_set          fsRead;
    HI_S32          fsSel;
    struct  timeval time;

    prctl(PR_SET_NAME, (unsigned long)"UARTOST_Thread", 0, 0, 0);
    pthread_detach(pthread_self());

    while (1)
    {
        if (bUartPause) {
            printf("### mcu pause ###\n");
            usleep(500 * 1000);
        } else {
            FD_ZERO(&fsRead);
            FD_SET(g_s32gUart2Fd, &fsRead);
            time.tv_sec = 3;
            time.tv_usec = 0;
            fsSel = select(g_s32gUart2Fd + 1, &fsRead, NULL, NULL, &time);
            
            if (fsSel)
            {
                ret = read(g_s32gUart2Fd, rbuf, RD_MSGBUF_LEN);
                g_timStamp[2] = getTimeUsec();


//                print_buffer(rbuf, ret); //debug
                
                if (ret < -1)
                {
                    MLOGD("uartMSG read error ret= %d \n", ret);
                    continue;
                }
                else
                {
                    putLen = __kfifo_put(&g_UartRecvFifo, rbuf, ret);
            
                    if (putLen == 0)
                    {
                        MLOGD("kfifo full... \n");
                    }
                }
            
                do
                {
                    readLen = HI_HAL_UART_RecvData(g_s32gUart2Fd,  g_frameBuf, sizeof(g_frameBuf));
            
                    if ( (readLen >= UF_MIN_LEN)  && (HI_NULL != g_cbkUartHostRcv))
                    {
                        g_timStamp[3] = getTimeUsec();
                        g_cbkUartHostRcv(g_frameBuf, readLen);
                    }
                }
                while (readLen > UF_MIN_LEN);
            }
            else if (fsSel < 0)
            {
                MLOGE("select failed!\n");
                continue;
            }
            else if (fsSel == 0 )
            {
                MLOGD("get uart char reselect \n");
                continue;
            }
        }
    }

    return NULL;
}


////////////////////////////////////////////////////////////////////////////////
HI_S32 HI_HAL_UARTMSG_Init(PFN_HI_HAL_UARTMSG_RCV_CALLBACK pRCVCallback)
{
    HI_S32 s32Ret;

    HI_UARTMSGCHECK_EXPR(g_bUartHostInit == HI_FALSE, HI_FAILURE);
    HI_UARTMSGCHECK_POINTER(pRCVCallback, HI_FAILURE);

    //3518EV300
    writew(0x1002, 0x112C0070);    //UART1_RXD
    writew(0x1052, 0x112C0074);    //UART1_TXD

    g_s32gUart2Fd = open("/dev/uartdev-1", O_RDWR | O_NOCTTY | O_NDELAY);

    if (g_s32gUart2Fd < 0)
    {
        g_s32gUart2Fd = -1;
        MLOGE("uartmsg : open %s with %d s32Ret = %d\n", "/dev/uartdev-X", O_RDWR, g_s32gUart2Fd);
        return HI_FAILURE;
    }

    s32Ret = ioctl(g_s32gUart2Fd, UART_CFG_BAUDRATE , UART_BAUDRATE);
    if (0 != s32Ret)
    {
        MLOGE("uartmsg : error !! set uart baudrate error, s32Ret = %d !!\n\n", s32Ret);
    }
    
	memset(g_USART_Receive_Buf, 0, sizeof(g_USART_Receive_Buf));
    __kfifo_init(&g_UartRecvFifo, g_USART_Receive_Buf, sizeof(g_USART_Receive_Buf));
    g_bUartHostInit = HI_TRUE;
    pthread_mutex_init(&s_tUartHostMutex, NULL);
    s32Ret = pthread_create(&g_tUartHostDetect, 0, UARTOST_Thread, NULL);

    if (s32Ret != 0 )
    {
        MLOGE("uartmsg : mcu host create thread fail.\n");
        close(g_s32gUart2Fd);
        g_s32gUart2Fd = -1;
        g_bUartHostInit = HI_FALSE;
        return s32Ret;
    }

    g_cbkUartHostRcv = pRCVCallback;
    MLOGD("uart host init ok \n");
    return HI_SUCCESS;
}

HI_S32 HI_HAL_UARTMSG_Deinit(HI_VOID)
{
    HI_S32 ret;

    if (g_bUartHostInit == HI_TRUE)
    {
        pthread_mutex_lock(&s_tUartHostMutex);
        g_bUartHostInit = HI_FALSE;
        ret = pthread_join(g_tUartHostDetect, NULL);

        if (ret != 0)
        {
            MLOGE("uartmsg : g_tUartHostDetect: pthread_join failed\n");
            return ret;
        }

        g_cbkUartHostRcv = HI_NULL;
        close(g_s32gUart2Fd);
        g_s32gUart2Fd = -1;

        pthread_mutex_unlock(&s_tUartHostMutex);
        pthread_mutex_destroy(&s_tUartHostMutex);
        memset(&s_tUartHostMutex, 0, sizeof(s_tUartHostMutex));
    }

    PrintTimeStamp();                                                           //防止编译器警告

    return HI_SUCCESS;
}

HI_S32 HI_HAL_UARTMSG_SendBuf(HI_U8* pBuf, HI_U32 bufLen)
{
    HI_S32 ret = HI_SUCCESS;

    HI_UARTMSGCHECK_EXPR(g_bUartHostInit == HI_TRUE, HI_FAILURE);
    HI_UARTMSGCHECK_POINTER(pBuf, HI_FAILURE);
    HI_UARTMSGCHECK_EXPR(bufLen > 0, HI_FAILURE);

    pthread_mutex_lock(&s_tUartHostMutex);
    g_timStamp[0] = getTimeUsec();

#if 0 //joki debug
    static char flag = 0;
    if (flag)
    {
        memset(pBuf, 0xAA, bufLen);
        flag = 0;
    }
    else
    {
        memset(pBuf, 0xAA, bufLen);
        flag = 1;
    }
#endif
    ret = write(g_s32gUart2Fd, pBuf, bufLen);
    //MLOGD("write uart fd=%d \n",g_s32gUart2Fd);
    //MLOGD("pBuf[0]:0x%x pBuf[1]:0x%x pBuf[2]:0x%x pBuf[3]:0x%x pBuf[4]:0x%x\n", pBuf[0], pBuf[1], pBuf[2], pBuf[3], pBuf[4]);
    g_timStamp[1] = getTimeUsec();
    pthread_mutex_unlock(&s_tUartHostMutex);

    if (ret != bufLen)
    {
        MLOGE("uartmsg : HI_HAL_UARTMSG_SendBuf : send (fd=%d) error(%d) !!\n", g_s32gUart2Fd, ret);
        ret = HI_FAILURE;
    }
    else
    {
        ret = HI_SUCCESS;
    }

    return HI_SUCCESS;
}

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
